import fs from 'fs';
import store from '../store';
import prettier from 'prettier';
import json2md, { DataObject } from 'json2md';
import { TValueOriginType } from '../types/normal';

/**
 * 统一生成文档行为
 *
 * 数据校验：通过提供的自定义方法，在方法中进行校验，如果不通过则 throw 一个错误出来，通过则正确返回
 */
export function generateFlow<T, M>(
    parseResult: T,
    options: {
        output: string;
        getFormatContentConfigs: (parseResult: T) => M;
        getMarkdownConfigs: (configs: M) => Array<DataObject>;

        // 自定义数据回调
        parseResultPoint?: (parseResult: T) => T;
        formatContentConfigsPoint?: (configs: M) => M;
        markdownJsonPoint?: (configs: Array<DataObject>) => Array<DataObject>;
        markdownContentPoint?: (mdContent: string) => string;
        success?: () => void;
    }
) {
    // ...
    try {
        // 自定义解析结果
        const parseResultTmp = options?.parseResultPoint?.(JSON.parse(JSON.stringify(parseResult)));
        if (parseResultTmp) parseResult = parseResultTmp;

        // 自定义 Markdown 文本
        let contentConfigs = options.getFormatContentConfigs(parseResult);
        const contentConfigsTmp = options?.formatContentConfigsPoint?.(contentConfigs);
        if (contentConfigsTmp) contentConfigs = contentConfigsTmp;

        // 自定义 Markdown 配置
        let markdownConfigs = options.getMarkdownConfigs(contentConfigs);
        const markdownConfigsTmp = options?.markdownJsonPoint?.(JSON.parse(JSON.stringify(markdownConfigs)));
        if (markdownConfigsTmp) markdownConfigs = markdownConfigsTmp;

        // 自定义 Markdown 内容
        let mdContent = json2md(markdownConfigs);
        const mdContentTmp = options?.markdownContentPoint?.(mdContent);
        if (mdContentTmp) mdContent = mdContentTmp;

        writeFileContent(options.output, mdContent);

        store.resetRandomCodeOneCharIndex();

        options?.success?.();

        // ...
    } catch (error) {
        store.resetRandomCodeOneCharIndex();
        throw error;
    }
}

/**
 * 读取文件
 */
export function readFileContent(filepath: string) {
    if (fs.existsSync(filepath)) {
        return fs.readFileSync(filepath, 'utf-8');
    } else {
        throw new Error('文件不存在');
    }
}

/**
 * 输出文件
 */
export function writeFileContent(output: string, content: string) {
    fs.writeFileSync(output, content);
}

/**
 * 转换数组中的元素为 Markdown 可以解析显示的值
 */
export function formatArrayItemToMdValue(array: Array<unknown>, config?: { length?: number; char?: string }) {
    const char = config?.char || '-';
    const length = config?.length || array.length;

    return Array(length)
        .fill('')
        .map((_, index) => {
            const item = array[index];
            if (Array.isArray(item)) {
                return item.length ? item : char;
            } else if (item instanceof Object) {
                return Object.keys(item).length ? item : char;
            } else if (typeof item === 'boolean') {
                return '' + item;
            } else if (![null, undefined, ''].includes(item as any)) {
                return item;
            } else {
                return char;
            }
        });
}

/**
 * 转换为 Markdown 可以解析显示的值（需要传入值的原本类型）
 *
 * 该工具函数暂时用于处理 Vue Props 中的 Prop 的 default 属性值
 *
 * 解析出的值类型与原本类型的映射关系查看 /src/parser/vue-sfc/utils.ts getObjectPropValue()
 */
export function formatToMdValueByType(valueInfo: { value: unknown; type: TValueOriginType | undefined }) {
    if (!valueInfo.type) return '-';

    switch (valueInfo.type) {
        case 'boolean': {
            return '' + valueInfo.value;
        }
        case 'null': {
            return 'null';
        }
        case 'undefined': {
            return 'undefined';
        }
        case 'function': {
            return toSingleLineForMarkdown(valueInfo.value as string);
        }
        default: {
            return valueInfo.value;
        }
    }
}

/**
 * 消除结尾分号
 */
export function fixEndSemicolon(code: string, options?: { isArray?: boolean }) {
    if (options?.isArray) {
        return code.replace(/\]\;(\n)?$/, ']');
    } else {
        return code.replace(/\}\;(\n)?$/, '}').replace(/\]\;(\n)?$/, ']');
    }
}

/**
 * 格式化 JS/TS 代码块
 */
export function formatCodeForScript(code: string, options?: { tabWidth?: number }) {
    const tabWidth = typeof options?.tabWidth === 'number' ? options.tabWidth : 4;
    let str = code.replace(/\r/g, '');
    str = prettier.format(str, { parser: 'babel', tabWidth });
    return str;
}

/**
 * 格式化对象
 */
export function formatCodeForObject(code: string, options?: { tabWidth?: number }) {
    const idenIndex = code.indexOf('{');
    code = 'const tcejbo = {' + code.substring(idenIndex + 1);
    code = formatCodeForScript(code, options);
    return code.replace('const tcejbo = ', '');
}

/**
 * 格式化匿名函数
 */
export function formatCodeForAnonymousFunction(code: string, options?: { tabWidth?: number }) {
    const funcIdenIndex = code.indexOf('function');
    code = 'function noitcnuf' + code.substring(funcIdenIndex + 8);
    code = formatCodeForScript(code, options);
    return code.replace('noitcnuf', '');
}

/**
 * 格式化数组
 */
export function formatCodeForArray(code: string, options?: { tabWidth?: number }) {
    const idenIndex = code.indexOf('[');
    code = 'const yarra = [' + code.substring(idenIndex + 1);
    code = formatCodeForScript(code, options);
    return code.replace('const yarra = ', '');
}

/**
 * 格式化 JSON
 */
export function formatCodeForJson(code: string, options?: { tabWidth?: number }) {
    const tabWidth = typeof options?.tabWidth === 'number' ? options.tabWidth : 4;
    return prettier.format(code, { parser: 'json', tabWidth });
}

/**
 * 按单行格式输出字符串
 * 转换为 Markdown 可以解析显示的值
 */
export function toSingleLineForMarkdown(code: string) {
    let str = code.replace(/\r/g, '');
    return str.replace(/\n/g, '<br>').replace(/\s{4}/g, '&nbsp;&nbsp;&nbsp;&nbsp;');
}

/**
 * 获取文件扩展名
 */
export function getFileExt(filepath: string) {
    return (filepath.split('.').pop() || '').toLowerCase();
}

/**
 * 不是空对象
 */
export function isNotEmptyObject(obj: { [key: string]: any }) {
    return !!Object.keys(obj).length;
}

/**
 * 返回指定位数的随机编码
 */
export function randomCode(digits: number) {
    const idenChars = ['@', '#', '%', '&', '`', ';', ':'];
    const numberChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    const letterChars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    const upperLetterChars = letterChars.map(c => c.toUpperCase());
    const specialChars = ['À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'ß', 'Ý', 'Þ'];
    const oneChars = ['⋜', '⋝', 'ƒ', '‰', '‱', '∀', '∂', '∄', '∉', '∌', '∑', '√', '∛', '∜', '∡', '∢', '∤', '∦', '∫', '∬', '∭', '∮', '∯', '∰', '∱', '∲', '∳', '∸', '∻', '∼', '∾'];

    if (digits === 1) {
        return oneChars[store.randomCodeOneCharIndex];
    }

    const codes = [];
    let chars: string[] = [];

    if (digits < 4) {
        chars = idenChars.concat(specialChars);
    } else if (digits < 7) {
        chars = idenChars.concat(specialChars).concat(upperLetterChars);
    } else {
        chars = numberChars.concat(letterChars).concat(upperLetterChars);
    }

    for (let i = 0; i < digits; i++) {
        codes[i] = chars[getRandomNumber(0, chars.length - 1)];
    }
    return codes.join('');
}

/**
 * 随机返回 min 和 max 之间的一个整数，包含 min 和 max
 */
function getRandomNumber(min: number, max: number) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

/**
 * 返回文本结尾的空格数
 */
export function getEndSpaceLen(content: string) {
    let oneLine = '';
    const arr = content.split('\n');
    if (arr.length) oneLine = arr.pop() || '';

    const matchGroup = oneLine.match(/(\s*$)/);
    if (matchGroup) {
        return matchGroup[0].length;
    } else {
        return 0;
    }
}

/**
 * 返回文本开头的空格数
 */
export function getStartSpaceLen(content: string, lineNum = 1) {
    let lineContent = '';
    const arr = content.split('\n');
    if (arr.length && lineNum <= arr.length) lineContent = arr[lineNum - 1];

    const matchGroup = lineContent.match(/(^\s*)/);
    if (matchGroup) {
        return matchGroup[0].length;
    } else {
        return 0;
    }
}

/**
 * 返回一定数量的空格
 */
export function getSpaceChars(spaceLen: number) {
    return Array(spaceLen).fill(' ').join('');
}

/**
 * 是否函数类型
 */
export function isFunctionType(val: unknown) {
    return Object.prototype.toString.call(val) === '[object Function]';
}

/**
 * 是否对象类型
 */
export function isObjectType(val: unknown) {
    return val !== null && typeof val === 'object';
}
